package aryn.framework.io.xml;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLbuilder {

	private Document doc;
	private List<Element> elements = new ArrayList<Element>();
	private int index = -1;
	
	public XMLbuilder() {
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			this.doc = docBuilder.newDocument();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}
	
	public void addElement(String name, String value) {
		Element element = doc.createElement(name);
		if (value != null)
			element.appendChild(doc.createTextNode(value));
		if(index == -1)
			doc.appendChild(element);
		else if (index >= 0 && index < elements.size())
			(elements.get(index)).appendChild(element);
		else
			throw new RuntimeException("Node "+index+" doesn't exist.");
		elements.add(element);
	}
	
	public void addElement(String name) {
		addElement(name, null);
	}
	
	public void addAttribute(String name, String value) {
		Attr attr = doc.createAttribute(name);
		attr.setValue(value);
		if (index >= 0 && index < elements.size())
			elements.get(elements.size()-1).setAttributeNode(attr);
		else
			throw new RuntimeException("Cannot add attribute to the node "+index+".");
	}
	
	public void openChild() {
		index = elements.size()-1;
//		System.out.println("WARNING! "+ node.getNodeValue() + " got either a text and a child.");
	}
	
	public void closeChild() {
		index--;
	}
	
	private static String getTagValue(String sTag, Element eElement) {
		Node node = eElement.getElementsByTagName(sTag).item(0);
		if (node == null) return null;
		NodeList nlList = node.getChildNodes();
	 
	    Node nValue = (Node) nlList.item(0);
	 
		return nValue.getNodeValue();
	}
	
	public void create(String filename) {
		try {
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer;
			transformer = transformerFactory.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new File(filename));
			transformer.transform(source, result);
			System.out.println("Successfully created file "+filename+".");
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}
	
	public void load(String filename) {
		try {
			File fXmlFile = new File(filename);
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder;
			dBuilder = dbFactory.newDocumentBuilder();
			doc = dBuilder.parse(fXmlFile);
			doc.getDocumentElement().normalize();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public List<String> elementsNames() {
		List<String> elements = new ArrayList<String>();
		NodeList nList = doc.getChildNodes();
		for(int i = 0; i < nList.getLength(); i++)
			elements.add(nList.item(i).getNodeName());
		return elements;
	}
	
	public List<String> elementsNames(String elementName) {
		List<String> elements = new ArrayList<String>();
		NodeList nList = doc.getElementsByTagName(elementName);
		for(int i = 0; i < nList.getLength(); i++)
			elements.add(nList.item(i).getNodeName());
		return elements;
	}
	
	public List<String> elementsValues() {
		List<String> elements = new ArrayList<String>();
		NodeList nList = doc.getChildNodes();
		for(int i = 0; i < nList.getLength(); i++)
			elements.add(nList.item(i).getNodeValue());
		return elements;
	}
	
	public List<String> elementsValues(String elementName) {
		List<String> elements = new ArrayList<String>();
		NodeList nList = doc.getElementsByTagName(elementName);
		for(int i = 0; i < nList.getLength(); i++)
			elements.add(nList.item(i).getNodeValue());
		return elements;
	}
}
